/**
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Request = require('./requests.js').Request;
var BatchRequest = require('./requests.js').BatchRequest;

/**
 * Constructs a new client with given API name and version.
 * @constructor
 *
 * @param {object} apiMeta Schema returned by Discovery API.
 */
function Client(apiMeta) {
  this.apiMeta = apiMeta;

  // generate helper methods
  this.registerHelpers_();
}

/**
 * @private
 * Registers request builders for existing API methods.
 */
Client.prototype.registerHelpers_ = function() {
  for (var i in this.apiMeta.methods) {
    var methodMeta = this.apiMeta.methods[i];
    this.extend_(this, methodMeta.id, this.generateHelper_(methodMeta));
  }
};

/**
 * @private
 * TODO(burcud): move to utils
 *
 * @param {?object} root Object to be extended.
 * @param {string} key Full key.
 * @param {?object} obj Object to extend root object with.
 * @return {object} Extended object.
 */
Client.prototype.extend_ = function(root, key, obj) {

  if (!root) root = {};
  var namespaceKeys = key.split('.');

  var chain = root;
  for (var i = 0; i < namespaceKeys.length; i++) {
    var chainKey = namespaceKeys[i];

    // if this is the last key, put obj in it.
    if (i == namespaceKeys.length - 1) {
      chain[chainKey] = obj;
    } else if (!chain[chainKey]) {
      chain[chainKey] = {};
    }

    // move to the next key
    chain = chain[chainKey];
  }

  return root;
};

/**
 * @private
 * Generate a request builder helper.
 *
 * @param {object} methodMeta Method's schema returned by Discovery API.
 * @return {Function} Function generated by methodMeta.
 */
Client.prototype.generateHelper_ = function(methodMeta) {

  var that = this;

  // generates a function to make a request
  // to the resource on given method
  return function(params, resource) {
    return that.newRequest(methodMeta.id, params, resource);
  };
};

/**
 * Constructs a request to method with given parameters.
 *
 * @param {string} methodName Full name of the method.
 * @param {?object} params Parameters.
 * @param {object=} opt_resource Optional resource.
 *
 * @return {Request} New Request object constructed with given args.
 */
Client.prototype.newRequest = function(methodName, params, opt_resource) {
  return new Request(this.apiMeta, methodName, params, opt_resource);
};

/**
 * Constructs a new batch request.
 *
 * @return {BatchRequest} New BatchRequest object.
 */
Client.prototype.newBatchRequest = function() {
  return new BatchRequest(this.apiMeta);
};

/**
 * Sets the given API key.
 *
 * @param {?string} apiKey API Key.
 *
 * @return {Client} Returns itself.
 */
Client.prototype.withApiKey = function(apiKey) {
  this.apiMeta.apiKey = apiKey;
  return this;
};

/**
 * Exporting Client.
 */
module.exports = Client;
